package eu.briano.suirvellancecamera;

import java.util.Timer;
import java.util.TimerTask;

import eu.briano.suirvellancecamera.OnImageReady.Context;

import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.os.AsyncTask;
import android.view.SurfaceHolder;
import android.view.View;

public class AcquireVideo extends Acquire   implements SurfaceHolder.Callback {
	
	private OnImageReady.Context context = new OnImageReady.Context();
	
	public AcquireVideo(Camera _c) {
		super(_c);
		context.startAcquireTs = Utils.now();
		
	}

	private boolean initDone= false;// TODO Auto-generated method stub
	private int bytePerPixel = 3 ;
	private int w,h ;
	private byte[] callbackBuffer  = null;
	private long lastProcessedImageTs = 0 ;
 



	@Override
	public void start(View v) {
		Log.v(Utils.logName,"start init done");
		try {
			if (!initDone ) {
				//Utils.logCameraInfos(c);
				Parameters params = c.getParameters();

				int [] size = Utils.selectCameraPreviewSize(c);

				w = size[0];
				h = size[1];

				int imageFormat = Utils.previewFormat;
				params.setPreviewFormat(imageFormat);
				params.setPreviewSize(w, h);
				int bitPerPixel  = ImageFormat.getBitsPerPixel(imageFormat);
				Log.v(Utils.logName,"AcquireVideo bitsperpixel:"+bytePerPixel);
				params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
				c.reconnect();
				c.setParameters(params);
				int bufferSize = w*h*((bitPerPixel/8)+1);
				if (callbackBuffer == null)
					callbackBuffer  = new byte[bufferSize];
				c.addCallbackBuffer(callbackBuffer);
				initDone  = true;
				Log.v(Utils.logName,"start init done");
			}

			PreviewCallback cb  = new PreviewCallback(){
				@Override
				public void onPreviewFrame(byte[] buffer, Camera ca) {
					Log.v(Utils.logName,"onPreviewFrame ");
					doAsyncProcess();
				}

			};
			c.setPreviewCallbackWithBuffer(cb);
		} catch (Exception e) {
			Log.e(Utils.logName,e.toString(),e);
		}
		Log.v(Utils.logName,"start done");
	}
	@Override
	public void stop(View v) {
		try {
			if (t != null && t.getStatus() != AsyncTask.Status.FINISHED) {
				Long  res = t.get();
				Log.v(Utils.logName,"stop doAsyncProcess stopped "+t.getStatus() + " result:  "+res);
			}
		} catch (Throwable t) {
			Log.v(Utils.logName,"stop doAsyncProcess cancel failed",t);
		}		
		c.stopPreview();
		c.addCallbackBuffer(null);
		callbackBuffer = null;
	}

	AsyncTask<Object, Integer, Long> t = null;



	private void doAsyncProcess() {
		try {
			if (t != null && t.getStatus() != AsyncTask.Status.FINISHED)
				t.cancel(true);
		} catch (Throwable t) {
			Log.v(Utils.logName,"doAsyncProcess cancel failed");
		}
		t =  new AsyncTask<Object, Integer, Long>(){
			@Override
			protected Long doInBackground(Object... params) {
				Camera.Parameters parameters = c.getParameters();
				Size size = parameters.getPreviewSize();
				int w = size.width ;
				int h =  size.height;
				
				context.frameFromStart++;
				
				context.processStartTs = Utils.now();
				if (onImageReady != null)
					onImageReady.callBack(w,h,callbackBuffer,context);

				long elapsed =  Utils.now() -lastProcessedImageTs ;
				long delay = (Utils.msPerFrame - elapsed) % Utils.msPerFrame;
				Log.v(Utils.logName, "sleep for  "+delay + " ms");
				if (delay > 0 ) {
					new Timer().schedule(new TimerTask() {
						@Override
						public void run() {
							c.addCallbackBuffer(callbackBuffer);
							lastProcessedImageTs = Utils.now() ;
						}
					}, delay) ;
				} else {
					c.addCallbackBuffer(callbackBuffer);
					lastProcessedImageTs = Utils.now() ;
				}
				return 0L;
			}
		};
		t.execute();
	};	

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		if (holder.getSurface() == null){
			// preview surface does not exist
			return;
		}	
		try {
			c.stopPreview();
		} catch (Exception e){
			// ignore: tried to stop a non-existent preview
		}        
		try {
			c.setPreviewDisplay(holder);
			c.startPreview();
		} catch (Throwable e) {
			Log.e(Utils.logName,"error on surfaceChanged",e);
		}
		Log.d(Utils.logName,"surfaceChanged done");
	}
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		try {
			c.setPreviewDisplay(holder);
			c.startPreview();
		} catch (Throwable e) {
			Log.e(Utils.logName,"error on surfaceCreated",e);
		}
		Log.d(Utils.logName,"surfaceCreated done");
	}
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		if (c != null  ) {
			try {
				c.stopPreview();
				c.release();
			} catch (Throwable e) {
				Log.v(Utils.logName," surfaceDestroyed camera release failed");
			}
		}
		Log.d(Utils.logName," surfaceDestroyed !");

	}	


}
